package nl.weeaboo.sh.view.anim;

import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;

import nl.weeaboo.game.gl.GLManager;
import nl.weeaboo.sh.Game;

public class Animation {
	
	private List<AnimationFrame> frames;
	private boolean looping;
	private Rectangle imageBounds;
	
	private Animation requested;
	private int active;
	private int time;
	
	public Animation() {
		frames = new ArrayList<AnimationFrame>();
		looping = true;
		
		reset();
	}
	
	//Functions
	public static Animation create(Game game, String baseImage, boolean looping,
			Object... frames)
	{
		Animation anim = new Animation();
		anim.setLooping(looping);
		for (int n = 0; n < frames.length; n += 2) {
			AnimationFrame frame = new AnimationFrame(
					game.getCharaImage(baseImage+'#'+frames[n]),
					(Integer)frames[n+1]);
			anim.addFrame(frame);
		}
		return anim;
	}
	
	public void reset() {
		requested = null;
		active = 0;
		time = 0;
	}
	
	public void addFrame(AnimationFrame f) {
		frames.add(f);
		recalculateImageBounds();
	}
	public void removeFrame(AnimationFrame f) {
		frames.remove(f);
		recalculateImageBounds();
	}
	
	public Animation update(int dt) {
		time += dt;
		
		AnimationFrame frame;
		while (time >= 0 && (frame = getCurrentFrame()) != null && time >= frame.getDuration()) {
			time -= frame.getDuration();

			if (requested != null && frame.canEscape()) {
				return next(requested);
			}
			
			active++;
			if (active >= frames.size() && looping) {
				active = 0;
			}
		}
		
		if (active >= frames.size()) {
			if (looping) {
				return update(0);
			} else if (requested != null) {
				return next(requested);
			}
		}
		
		return this;
	}
	
	public void draw(GLManager glm, boolean mirror) {
		AnimationFrame frame = getCurrentFrame();
		if (frame != null) {
			frame.draw(glm, mirror);
		}
	}

	public void request(Animation anim) {
		requested = anim;
	}
	public Animation next(Animation anim) {
		int t = time;
		reset();
		return anim.update(t);
	}
	
	protected void recalculateImageBounds() {
		Rectangle bounds = new Rectangle(0, 0, -1, -1);
		if (!frames.isEmpty()) {
			bounds.setBounds(frames.get(0).getImageBounds());
			for (int n = 1; n < frames.size(); n++) {
				bounds.union(frames.get(n).getImageBounds());
			}
		}
		imageBounds = bounds;
	}
	
	//Getters
	public AnimationFrame getCurrentFrame() {
		return (active >= 0 && active < frames.size() ? frames.get(active) : null);
	}
	public AnimationFrame getFrame(int index) {
		return (index >= 0 && index < frames.size() ? frames.get(index) : null);
	}
	public AnimationFrame getLastFrame() { return getFrame(getFrameCount()-1); }
	public int getFrameCount() { return frames.size(); }
	public Rectangle getImageBounds() { return imageBounds; }	
	
	//Setters
	public void setLooping(boolean l) { looping = l; }
	
}
